package org.compactmvc.services.async.rest
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import org.compactmvc.interfaces.IModel;
	import org.compactmvc.patterns.Controller;
	import org.compactmvc.patterns.Model;
	import org.compactmvc.services.interfaces.IRESTfulService;
	import org.compactmvc.services.vo.RestServiceItemVO;
	
	public class RESTfulService extends Model implements IModel, IRESTfulService
	{
		public static var NAME:String = 'RESTfulService';

		protected var _queueMap:Vector.<RestServiceItemVO>;
		protected var _requestSequence:Number = 0;
		protected var _dataLoader:URLLoader;
		protected var _currentItem:RestServiceItemVO;		
		protected var _uri:String;

		public function RESTfulService(name:String, controller:Controller)
		{
			super(name, controller);
			
			_queueMap = new Vector.<RestServiceItemVO>();
			
			_dataLoader = new URLLoader();
			_dataLoader.addEventListener(ProgressEvent.PROGRESS, loaderProgressHandler, false, 0, true);
			_dataLoader.addEventListener(IOErrorEvent.IO_ERROR, loaderIOErrorHandler, false, 0, true);
			_dataLoader.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
			_dataLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderSecurityErrorHandler, false, 0, true);
		}
		
		public function dispose():void
		{		
			_dataLoader.close();
			_dataLoader.removeEventListener(ProgressEvent.PROGRESS, loaderProgressHandler );
			_dataLoader.removeEventListener(IOErrorEvent.IO_ERROR, loaderIOErrorHandler);
			_dataLoader.removeEventListener(Event.COMPLETE, loaderCompleteHandler);
			_dataLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderSecurityErrorHandler);	
			_dataLoader = null;
		}
		
		override public function removeHandler():void
		{
			dispose();
		}
		
		/**
		 * loads a xml file from the given url
		 * @param url
		 * 
		 */		
		protected function load(request:URLRequest, name:String=null, resultHandler:Function=null, faultHandler:Function=null, mockupFilePath:String=null):void 
		{
			var vo:RestServiceItemVO = new RestServiceItemVO();
			vo.request = request;
			vo.name = name;
			vo.resultHandler = resultHandler;
			vo.faultHandler = faultHandler;
			vo.mockupFilePath = mockupFilePath;
			
			addToQueue(vo);
			
		}
		
		/**
		 * adds a new item to the  queue list
		 * @param item
		 * 
		 */		
		private function addToQueue(item:RestServiceItemVO):void
		{
			_queueMap.push(item);
			
			if(!_currentItem)
				nextItem();	
		}
		
		/**
		 * remove a queue item and close loading operation
		 * @param itemToRemove
		 * @return 
		 * 
		 */		
		public function removeFromQueue(itemToRemove:RestServiceItemVO):RestServiceItemVO
		{
			//remove from queue list
			for (var i:int = 0; i < _queueMap.length; i++)
			{
				var item:RestServiceItemVO = _queueMap[i];
				if(item == itemToRemove)
				{
					_queueMap.splice(i, 1);			
					break;
				}	
			}	
			
			//if item is current, stop loading
			if(_currentItem == itemToRemove)
			{
				_dataLoader.close();
				_currentItem = null;
				nextItem();
				return itemToRemove;
			}
			
			return itemToRemove;			
		}
		
		/**
		 * starts loading the next queue items xml file 
		 * 
		 */		
		private function nextItem():void
		{
			_currentItem = null;
			
			if(_queueMap.length == 0)
				return;
			
			_currentItem = _queueMap.shift();
			
			//mockup?
			if(_currentItem.mockupFilePath)
			{
				_currentItem.request = new URLRequest(_currentItem.mockupFilePath);
			}
			
			try 
			{	
				_dataLoader.load(_currentItem.request);	
			} 
			catch (error:Error) 
			{
				var msg:String = 'Unable to load requested document:' + error.message;
				
				if(_currentItem.faultHandler != null)
					_currentItem.faultHandler(msg);
				
				errorHandler(msg);
				
				nextItem();				
			}		
		}
		
		private function loaderProgressHandler( e:ProgressEvent ):void
		{
			progressHandler(e.bytesLoaded/e.bytesTotal);
		}
		
		private function loaderIOErrorHandler(e:IOErrorEvent):void 
		{
			IOErrorHandler(e.text);
			
			nextItem();
		}
		
		private function loaderSecurityErrorHandler(e:SecurityErrorEvent):void
		{
			securityErrorHandler(e.text);
			
			nextItem();
		}
		
		private function loaderCompleteHandler(e:Event):void 
		{		
			if(e.target.data)
			{
				_currentItem.data = e.target.data;
				
				if(_currentItem.resultHandler != null)
					_currentItem.resultHandler(_currentItem);
				
				completeHandler(_currentItem);		
			}			
			else
			{
				var msg:String = 'Object is not valid!';
				
				if(_currentItem.faultHandler != null)
					_currentItem.faultHandler(msg);
				
				errorHandler(msg);
			}
			nextItem();
		}
		
		public function progressHandler(progress:Number):void
		{
			//overriden by subclass
		}
		
		public function IOErrorHandler(message:String):void 
		{
			//overriden by subclass
		}
		
		public function errorHandler(message:String):void 
		{
			//overriden by subclass
		}
		
		public function completeHandler(result:RestServiceItemVO):void 
		{
			//overriden by subclass
		}
		
		public function securityErrorHandler(message:String):void
		{
			//overriden by subclass
		}
		
		public function get uri():String
		{
			return _uri;
		}

		public function set uri(value:String):void
		{
			_uri = value;
		}


	}
}